package com.leinardi.android.speeddial;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

public class DragDoubleTouchViewAdapter implements View.OnTouchListener {
    private int screenWidth;
    private int screenHeight;
    private int statusHeight=0;

    private boolean autoKeepSide=false;
    private boolean isLongClickModule;

    private Runnable halfHoveringStateChangeCheckRun=null;
    private HalfHoveringStateChangeCallback halfHoveringStateChangeCallback;

    private Handler handler;

    private int clickCount = 0;//记录连续点击次数

    /**
     * 自定义回调接口
     */
    private DoubleClickCallback doubleClickCallback;
    private Runnable doubleClickCheckRun=null;

    private LongClickCallback longClickCallback;
    private Runnable longClickCheckRun=null;

    private ClickCallback clickCallback;

    private SideChangeCallback _sideChangeCallback=new SideChangeCallback() {
        @Override
        public void onSideChanged(int expansionMode) {
            if(sideChangeCallback!=null)
                sideChangeCallback.onSideChanged(expansionMode);
        }
    };

    private SideChangeCallback sideChangeCallback;

    private View clickView,dragView;

    public DragDoubleTouchViewAdapter(View view, View dragView, int screenWidth, int screenHeight, int statusHeight){
        clickView =view;
        clickView.setOnTouchListener(this);
        this.dragView=dragView;
        this.screenWidth=screenWidth;
        this.screenHeight=screenHeight;
        this.statusHeight=statusHeight;
        clickView.setOnClickListener(v -> {
            if(clickCallback!=null)
                clickCallback.onClick();
        });
        handler = new Handler();
    }

    public interface DoubleClickCallback {
        void onDoubleClick();
    }

    public interface LongClickCallback {
        void onLongClick();
    }

    public interface ClickCallback {
        void onClick();
    }

    public interface HalfHoveringStateChangeCallback{
        boolean isHalfHoveringAble();
        boolean isHalfHoveringExpend();
        void onHalfHoveringStateChangeStart(boolean expand);
        void onHalfHoveringStateChangeEnd(boolean expand);
    }

    public interface SideChangeCallback {
        void onSideChanged(@AbstractSpeedDialView.ExpansionMode int expansionMode);
    }

    private int lastX;
    private int lastY;

    private boolean isDrag;

    @Override
    public boolean onTouch(View v,MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                isLongClickModule=isDrag = false;
                v.getParent().requestDisallowInterceptTouchEvent(true);
                lastX = rawX;
                lastY = rawY;
                //Log.e("down---->", "getX=" + getX() + "；screenWidthHalf=" + screenWidthHalf);
                clickCount++;
                if(clickCount==1) {
                    longClickCheckRun=()->{
                        isLongClickModule =true;
                    };
                    handler.postDelayed(longClickCheckRun, 300);//长按时间
                    doubleClickCheckRun = () -> {
                        if(!isDrag) {
                            if (clickCount == 1) {
                                if (isLongClickModule) {
                                    if (longClickCallback != null)
                                        longClickCallback.onLongClick();
                                    isLongClickModule = false;
                                } else
                                    v.performClick();
                            } else if (clickCount == 2) {
                                if (doubleClickCallback != null)
                                    doubleClickCallback.onDoubleClick();
                            }
                        }
                        handler.removeCallbacksAndMessages(this);
                        //清空handler延时，并防内存泄漏
                        clickCount = 0;//计数清零
                        doubleClickCheckRun=null;
                    };
                    handler.postDelayed(doubleClickCheckRun, 400);//双击间隔
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //当滑动时背景为选中状态 //检测是否长按,在非长按时检测
                /*if (!isLongClickModule) {
                    isLongClickModule = isLongPressed(event.getDownTime(), event.getEventTime(), 300);
                    Timber.d( "longClick checked");
                }*/
                if(isLongClickModule){
                    //计算手指移动了多少
                    int dx = rawX - lastX;
                    int dy = rawY - lastY;

                    if(!isDrag) {
                        //这里修复一些手机无法触发点击事件的问题
                        int distance = (int) Math.sqrt(dx * dx + dy * dy);

                        //Log.e("distance---->", distance + "");
                        if (distance > 30) {//给个容错范围，不然有部分手机还是无法点击
                            isDrag = true;
                            if(isHalfHoveringAble()&&!isHalfHoveringExpend()){
                                toggleHalfHovering();
                            }
                        }
                    }
                    if(isDrag){
                        float x = dragView.getX() + dx;
                        float y = dragView.getY() + dy;

                        //检测是否到达边缘 左上右下
                        x = x < 0 ? 0 : x > screenWidth - dragView.getWidth() ? screenWidth - dragView.getWidth() : x;
                        // y = y < statusHeight ? statusHeight : (y + getHeight() >= screenHeight ? screenHeight - getHeight() : y);
                        if (y < 0) {
                            y = 0;
                        }
                        if (y > screenHeight - statusHeight - dragView.getHeight()) {
                            y = screenHeight - statusHeight - dragView.getHeight();
                        }
                        dragView.setX(x);
                        dragView.setY(y);

                        lastX = rawX;
                        lastY = rawY;

                        //Log.e("move---->", "getX=" + getX() + "；screenWidthHalf=" + screenWidthHalf + " " + isDrag+"  statusHeight="+statusHeight+ " virtualHeight"+virtualHeight+ " screenHeight"+ screenHeight+"  getHeight="+getHeight()+" y"+y);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                if (isDrag) {
                    //Log.e("ACTION_UP---->", "getX=" + getX() + "；screenWidthHalf=" + screenWidthHalf);
                    /*if (rawX >= (screenWidth+dragView.getWidth()) / 2)
                        sideChangeCallback.onSideChanged(AbstractSpeedDialView.ExpansionMode.RIGHT);
                    else if(rawX <= (screenWidth-dragView.getWidth()) / 2)
                        sideChangeCallback.onSideChanged(AbstractSpeedDialView.ExpansionMode.LEFT);*/

                    if(autoKeepSide) {
                        if (rawX >= screenWidth / 2) {
                            dragView.animate().setInterpolator(new DecelerateInterpolator())
                                    .setDuration(500)
                                    .xBy(screenWidth - dragView.getWidth() - dragView.getX())
                                    .start();
                        } else {
                            dragView.animate().setInterpolator(new DecelerateInterpolator())
                                    .setDuration(500)
                                    .xBy(0)
                                    .start();
                        }
                    }
                    isDrag = false;
                }
                clickView.setPressed(false);

                if(isHalfHoveringAble()&&halfHoveringStateChangeCheckRun == null){
                    if(longClickCheckRun!=null&&!isHalfHoveringExpend()) {
                        handler.removeCallbacks(longClickCheckRun);
                        longClickCheckRun=null;
                    }

                    if(doubleClickCheckRun!=null&&!isHalfHoveringExpend()) {
                        handler.removeCallbacks(doubleClickCheckRun);
                        doubleClickCheckRun=null;
                    }

                    if(clickCount==1&&!isDrag&&!isHalfHoveringExpend()) {
                        clickCount = 0;//计数清零
                        toggleHalfHovering();
                    }
                    delayHalfHovering();
                }

                if(longClickCheckRun!=null) {
                    handler.removeCallbacks(longClickCheckRun);
                    longClickCheckRun = null;
                }
                break;
        }
        //如果是拖拽则消耗事件，否则正常传递即可。
        return true;//isDrag||doubleClickCheckRun!=null|| super.onTouchEvent(event);
    }

    public void delayHalfHovering(){
        if(halfHoveringStateChangeCheckRun!=null)
            handler.removeCallbacksAndMessages(halfHoveringStateChangeCheckRun);
        halfHoveringStateChangeCheckRun = () -> {
            toggleHalfHovering();
            handler.removeCallbacksAndMessages(this);
            halfHoveringStateChangeCheckRun = null;
        };
        handler.postDelayed(halfHoveringStateChangeCheckRun, 4000);
    }

    public void toggleHalfHovering(){
        if(!isHalfHoveringAble()) return;
        halfHovering(!isHalfHoveringExpend());
    }

    public void halfHovering(Boolean expend){
        if(expend){
            if(dragView.getX()<0){
                halfHoveringStateChangeCallback.onHalfHoveringStateChangeStart(true);
                dragView.animate().setInterpolator(new DecelerateInterpolator())
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation, boolean isReverse) {
                                halfHoveringStateChangeCallback.onHalfHoveringStateChangeEnd(true);
                            }
                        })
                        .setDuration(500)
                        .xBy(0)
                        .start();
            }else if(dragView.getX()>screenWidth - dragView.getWidth()){
                halfHoveringStateChangeCallback.onHalfHoveringStateChangeStart(true);
                dragView.animate().setInterpolator(new DecelerateInterpolator())
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation, boolean isReverse) {
                                halfHoveringStateChangeCallback.onHalfHoveringStateChangeEnd(true);
                            }
                        })
                        .setDuration(500)
                        .xBy(screenWidth - dragView.getWidth() - dragView.getX())
                        .start();
            }
        }else{
            float tempFloat=dragView.getWidth()*0.6f;
            if (isHoveringLeft()) {
                halfHoveringStateChangeCallback.onHalfHoveringStateChangeStart(false);
                dragView.animate().setInterpolator(new DecelerateInterpolator())
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation, boolean isReverse) {
                                halfHoveringStateChangeCallback.onHalfHoveringStateChangeEnd(false);
                            }
                        })
                        .setDuration(500)
                        .xBy(-tempFloat)
                        .start();
            } else if (isHoveringRight()) {
                halfHoveringStateChangeCallback.onHalfHoveringStateChangeStart(false);
                dragView.animate().setInterpolator(new DecelerateInterpolator())
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation, boolean isReverse) {
                                halfHoveringStateChangeCallback.onHalfHoveringStateChangeEnd(false);
                            }
                        })
                        .setDuration(500)
                        .xBy(screenWidth - dragView.getWidth() - dragView.getX() + tempFloat)
                        .start();
            }
        }
    }

    private boolean isHalfHoveringExpend(){
        return halfHoveringStateChangeCallback.isHalfHoveringExpend();
    }

    private boolean isHalfHoveringAble(){
        return halfHoveringStateChangeCallback!=null&&halfHoveringStateChangeCallback.isHalfHoveringAble();
    }

    public boolean isAutoKeepSide() {
        return autoKeepSide;
    }

    private boolean isHoveringLeft(){
        return dragView.getX()==0;
    }

    private boolean isHoveringRight(){
        return dragView.getX()==(screenWidth - dragView.getWidth());
    }

    public void setAutoKeepSide(boolean autoKeepSide) {
        this.autoKeepSide = autoKeepSide;
    }

    public void setDoubleClickCallback(DoubleClickCallback mCallback) {
        this.doubleClickCallback = mCallback;
    }

    public void setLongClickCallback(LongClickCallback mLongClickCallback) {
        this.longClickCallback = mLongClickCallback;
    }

    public void setClickCallback(ClickCallback clickCallback) {
        this.clickCallback = clickCallback;
    }

    public void setHalfHoveringStateChangeCallback(HalfHoveringStateChangeCallback callback){
        this.halfHoveringStateChangeCallback=callback;
    }

    public void setSideChangeCallback(SideChangeCallback callback){
        this.sideChangeCallback=callback;
    }
}
